﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SharpDepend.Classes
{
    /// <summary>
    /// Class that could instaniate in all classes that you want to track.
    /// <para>By giving the instance to track passing into constructor parameter</para>
    /// <para>you will be able to watch all trackable objects.</para>
    /// </summary>
    public class InstanceCounter
    {
        private static Dictionary<Type, int> sAllInstances = new Dictionary<Type, int>();

        private object mTrackedObject;

        /// <summary>
        /// Add this instances for all classes you want to track.
        /// <para>Declare it as a member and create instance in the constructor.</para>
        /// </summary>
        /// <param name="trackedObject">Instance to track.</param>
        public InstanceCounter(object trackedObject)
        {
            mTrackedObject = trackedObject;

            Type instanceType = trackedObject.GetType();

            lock (sAllInstances)
            {
                if (!sAllInstances.ContainsKey(instanceType))
                {
                    sAllInstances.Add(instanceType, 1);
                }
                else
                {
                    ++sAllInstances[instanceType];
                }
            }
        }

        /// <summary>
        /// Should be called when the tracked instance is no more being used by anyone.
        /// <para>This InstanceCounter will then as well not be used by anyone and will</para>
        /// <para>call the destructor.</para>
        /// </summary>
        ~InstanceCounter()
        {
            Type instanceType = mTrackedObject.GetType();

            lock (sAllInstances)
            {
                if (sAllInstances.ContainsKey(instanceType))
                {
                    int i = --sAllInstances[instanceType];

                    if (i == 0)
                    {
                        sAllInstances.Remove(instanceType);
                    }
                }
                else
                {
                    throw new Exception("Internal error in InstanceCounter destructor.");
                }
            }
        }

        /// <summary>
        /// Report current state of all instances that is tracked. It will
        /// <para>run the GC collect first to get the most updated state.</para>
        /// </summary>
        /// <returns>String of a report.</returns>
        public static string ReportStatistic()
        {
            StringBuilder sb = new StringBuilder();

            lock (sAllInstances)
            {
                //System.GC.Collect();

                foreach (var instance in sAllInstances)
                {
                    sb.Append(instance.Key.Name);
                    sb.Append(": ");
                    sb.Append(instance.Value);
                    sb.Append(" instances.\n");
                }
            }

            return sb.ToString();
        }
    }
}
